﻿' ----------------------------------------------------------------------------------
' Microsoft Developer & Platform Evangelism
' 
' Copyright (c) Microsoft Corporation. All rights reserved.
' 
' THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
' EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES 
' OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
' ----------------------------------------------------------------------------------
' The example companies, organizations, products, domain names,
' e-mail addresses, logos, people, places, and events depicted
' herein are fictitious.  No association with any real company,
' organization, product, domain name, email address, logo, person,
' places, or events is intended or should be inferred.
' ----------------------------------------------------------------------------------

Imports Microsoft.Samples.WindowsPhoneCloud.StorageClient
Imports Microsoft.Samples.WindowsPhoneCloud.StorageClient.Credentials
Imports Microsoft.Samples.WindowsPhoneCloud.Phone.Models
Imports System.Text
Imports System.Runtime.Serialization
Imports System.Net.Browser
Imports System.IO
Imports System.Globalization

Namespace Push

    Public Class SamplePushUserRegistrationClient
        Implements ISamplePushUserRegistrationClient
        Private Const RegisterNotificationOperation As String = "/register"
        Private Const UnregisterNotificationOperation As String = "/unregister"
        Private Const GetUpdatesNotificationOperation As String = "/updates"

        Private ReadOnly serviceEndpoint As Uri
        Private ReadOnly storageCredentials As IStorageCredentials
        Private ReadOnly applicationId As String

        Public Sub New(ByVal serviceEndpoint As Uri, ByVal storageCredentials As IStorageCredentials, ByVal applicationId As String)
            Me.serviceEndpoint = serviceEndpoint
            Me.storageCredentials = storageCredentials
            Me.applicationId = applicationId
        End Sub

        Public Sub Connect(ByVal callback As Action(Of SamplePushUserRegistrationResponse(Of String))) Implements ISamplePushUserRegistrationClient.Connect
            Dim registerOperationUriBuilder = New UriBuilder(Me.serviceEndpoint)
            registerOperationUriBuilder.Path &= RegisterNotificationOperation

            PushContext.Current.Connect(Sub(c) ExecutePostServiceOperation(Of String)(registerOperationUriBuilder.Uri, Me.storageCredentials, c.ChannelUri, Me.applicationId, callback))
        End Sub

        Public Sub Disconnect(ByVal callback As Action(Of SamplePushUserRegistrationResponse(Of String))) Implements ISamplePushUserRegistrationClient.Disconnect
            If PushContext.Current.NotificationChannel IsNot Nothing Then
                Dim channelUri = PushContext.Current.NotificationChannel.ChannelUri
                Dim unregisterOperationUriBuilder = New UriBuilder(Me.serviceEndpoint)

                unregisterOperationUriBuilder.Path &= UnregisterNotificationOperation
                ExecutePostServiceOperation(Of String)(unregisterOperationUriBuilder.Uri, Me.storageCredentials, channelUri, Me.applicationId, callback)
            Else
                callback(New SamplePushUserRegistrationResponse(Of String)(String.Empty, Nothing))
            End If

            PushContext.Current.Disconnect()
        End Sub

        Public Sub GetUpdates(ByVal callback As Action(Of SamplePushUserRegistrationResponse(Of String()))) Implements ISamplePushUserRegistrationClient.GetUpdates
            If PushContext.Current.NotificationChannel IsNot Nothing Then
                Dim channelUri = PushContext.Current.NotificationChannel.ChannelUri
                Dim getUpdatesOperationUriBuilder = New UriBuilder(Me.serviceEndpoint)
                getUpdatesOperationUriBuilder.Path &= GetUpdatesNotificationOperation

                ExecuteGetServiceOperation(Of String())(getUpdatesOperationUriBuilder.Uri, Me.storageCredentials, channelUri, Me.applicationId, callback)
            End If
        End Sub

        Private Shared Sub ExecuteGetServiceOperation(Of T)(ByVal serviceOperationUri As Uri, ByVal storageCredentials As IStorageCredentials, ByVal channelUri As Uri, ByVal applicationId As String, ByVal callback As Action(Of SamplePushUserRegistrationResponse(Of T)))
            Dim deviceId As String = App.GetDeviceId()
            Dim getOperationUri = New Uri(String.Format(CultureInfo.InvariantCulture, "{0}?applicationId={1}&deviceId={2}", serviceOperationUri, applicationId, deviceId))

            Dim request = WebRequestCreator.ClientHttp.Create(getOperationUri)
            request.Method = "GET"

            Try
                storageCredentials.SignRequest(request, -1)
                request.BeginGetResponse(
                    Sub(ar)
                        Dim result As T = Nothing
                        Try
                            Dim response = request.EndGetResponse(ar)
                            Dim serializer = New DataContractSerializer(GetType(T))
                            result = CType(serializer.ReadObject(response.GetResponseStream()), T)
                            callback(New SamplePushUserRegistrationResponse(Of T)(result, Nothing))
                        Catch exception As Exception
                            callback(New SamplePushUserRegistrationResponse(Of T)(Nothing, If(StorageClientExceptionParser.ParseStringWebException(TryCast(exception, WebException)), exception)))
                        End Try
                    End Sub, Nothing)
            Catch exception As Exception
                callback(New SamplePushUserRegistrationResponse(Of T)(Nothing, exception))
            End Try
        End Sub

		Private Shared Sub ExecutePostServiceOperation(Of T)(ByVal serviceOperationUri As Uri, ByVal storageCredentials As IStorageCredentials, ByVal channelUri As Uri, ByVal applicationId As String, ByVal callback As Action(Of SamplePushUserRegistrationResponse(Of T)))
            Dim request = WebRequestCreator.ClientHttp.Create(serviceOperationUri)
            request.Method = "POST"
            request.ContentType = "text/xml"

            Dim postData = String.Empty
            Using stream = New MemoryStream()
                Dim serializer = New DataContractSerializer(GetType(PushUserServiceRequest))
                Dim deviceId As String = App.GetDeviceId()
                Dim newPushUserRegistration = New PushUserServiceRequest With {.ApplicationId = applicationId, .DeviceId = deviceId, .ChannelUri = channelUri}
                serializer.WriteObject(stream, newPushUserRegistration)

                Dim contextAsByteArray() As Byte = stream.ToArray()
                postData = Encoding.UTF8.GetString(contextAsByteArray, 0, contextAsByteArray.Length)
            End Using

            Try
                storageCredentials.SignRequest(request, postData.Length)
                request.BeginGetRequestStream(Sub(ar)
                                                  Dim postStream = request.EndGetRequestStream(ar)
                                                  Dim byteArray = Encoding.UTF8.GetBytes(postData)
                                                  postStream.Write(byteArray, 0, postData.Length)
                                                  postStream.Close()
                                                  request.BeginGetResponse(Sub(asyncResult)
                                                                               Dim result As T = Nothing
                                                                               Try
                                                                                   Dim response = request.EndGetResponse(asyncResult)
                                                                                   Dim serializer = New DataContractSerializer(GetType(T))
                                                                                   result = CType(serializer.ReadObject(response.GetResponseStream()), T)
                                                                                   callback(New SamplePushUserRegistrationResponse(Of T)(result, Nothing))
                                                                               Catch exception As Exception
                                                                                   callback(New SamplePushUserRegistrationResponse(Of T)(Nothing, If(StorageClientExceptionParser.ParseStringWebException(TryCast(exception, WebException)), exception)))
                                                                               End Try
                                                                           End Sub, Nothing)
                                              End Sub, request)
            Catch exception As Exception
                callback(New SamplePushUserRegistrationResponse(Of T)(Nothing, exception))
            End Try
        End Sub
    End Class
End Namespace